﻿using DevExpress.ExpressApp;
using DevExpress.ExpressApp.DC;
using DevExpress.ExpressApp.Updating;
using DevExpress.Persistent.Base;
using DevExpress.Xpo;
using System.ComponentModel;

namespace EasyXaf.DataDictionaries;

public sealed class DataDictionariesModule : ModuleBase
{
    public DataDictionariesModule()
    {
        RequiredModuleTypes.Add(typeof(DevExpress.ExpressApp.SystemModule.SystemModule));
    }

    public override IEnumerable<ModuleUpdater> GetModuleUpdaters(IObjectSpace objectSpace, Version versionFromDB)
    {
        return new ModuleUpdater[]
        {
            new DataDictionaryUpdater(objectSpace, versionFromDB)
        };
    }

    public override void CustomizeTypesInfo(ITypesInfo typesInfo)
    {
        base.CustomizeTypesInfo(typesInfo);

        ITypeInfo dataDictionaryItemTypeInfo = null;

        // typesInfo.PersistentTypes包含持久化类型与非持久化类型，这一块在文章中有介绍
        // https://www.cnblogs.com/haoxj/p/16834882.html
        foreach (var persistentTypeInfo in typesInfo.PersistentTypes.Where(p => p.IsPersistent))
        {
            // 从persistentTypeInfo中查询出类型为DataDictionaryItem的成员
            // 这里排除了字段，只对属性进行处理
            var members = persistentTypeInfo.Members
                .Where(m => m.IsProperty)
                .Where(m => m.MemberType == typeof(XPCollection<DataDictionaryItem>)
                        || m.MemberType == typeof(DataDictionaryItem));

            foreach (var member in members)
            {
                // 符合数据字典的要求是在属性中添加DataDictionaryAttribute，并且其DataDictionaryName属性不为空
                var attribute = member.FindAttribute<DataDictionaryAttribute>();
                if (attribute != null && !string.IsNullOrWhiteSpace(attribute.DataDictionaryName))
                {
                    // 在TypesInfo中查找出DataDictionaryItem对应的TypeInfo
                    dataDictionaryItemTypeInfo ??= typesInfo.FindTypeInfo(typeof(DataDictionaryItem));

                    // 在DataDictionaryItem中添加成员，名称为当前成员与其所在类的信息组合，是为了保证唯一
                    // 字典项成员类型为XPCollection<>，它们之间的关系为一对多
                    var dictItemMember = dataDictionaryItemTypeInfo.CreateMember(
                        $"{persistentTypeInfo.Name}_{member.Name}",
                        typeof(XPCollection<>).MakeGenericType(persistentTypeInfo.Type));

                    // 关系名也是一个信息的组合，也是为了保证唯一
                    var associationName = $"{persistentTypeInfo.Name}_{member.Name}_{nameof(DataDictionaryItem)}";

                    // 向字典项成员中添加AssociationAttribute，注意其中的类型为elementType，不是字典项成员的类型
                    // 操作成员时，都选择了跳过刷新，刷新会放到后面一起执行（可以减少性能的损耗）
                    dictItemMember.AddAttribute(new AssociationAttribute(associationName, persistentTypeInfo.Type), true);

                    // 在DataDictionaryItem中隐藏新添加的成员是必要的，因为不需要对其显示及操作
                    dictItemMember.AddAttribute(new BrowsableAttribute(false), true);

                    // 在XPO中AssociationAttribute是双向的，所关联的属性都要有
                    member.AddAttribute(new AssociationAttribute(associationName, typeof(DataDictionaryItem)), true);

                    // 当前成员中如果已有数据来源，则采用已有的，没有则添加一个
                    // 默认数据源的条件为：[DataDictionary.Name]='所对应的字典名'
                    if (member.FindAttribute<DataSourceCriteriaAttribute>() == null
                        && member.FindAttribute<DataSourceCriteriaPropertyAttribute>() == null
                        && member.FindAttribute<DataSourcePropertyAttribute>() == null)
                    {
                        member.AddAttribute(new DataSourceCriteriaAttribute($"[DataDictionary.Name]='{attribute.DataDictionaryName}'"), true);
                    }

                    // 统一刷新成员
                    ((XafMemberInfo)member).Refresh();
                    ((XafMemberInfo)dictItemMember).Refresh();
                }
            }
        }
    }
}
